/**
 * GENPlusDroid
 * Copyright 2011 Stephen Damm (Halsafar)
 * All rights reserved.
 * shinhalsafar@gmail.com
 */

#include <jni.h>

#include "ctype.h"

#include "libpng/png.h"

#include "common.h"
#include "GraphicsDriver.h"
#include "InputHandler.h"

#include "gambatte.h"
#include <resample/resamplerinfo.h>

#define TURBO_FRAMES_TO_EMULATE 10

enum Buttons
{
     BUTTON_INDEX_B = 0,
     BUTTON_INDEX_A,
     BUTTON_INDEX_START,
     BUTTON_INDEX_SELECT,
     BUTTON_INDEX_REWIND,
     BUTTON_INDEX_FORWARD,
     BUTTON_INDEX_LEFT,
     BUTTON_INDEX_UP,
     BUTTON_INDEX_RIGHT,
     BUTTON_INDEX_DOWN,
     BUTTON_INDEX_COUNT
};


static class GbcInput : public Gambatte::InputGetter
{
public:
	unsigned bits;
	unsigned operator()() { return bits; }
} gbcInput;


class Application
{
public:
     Application();
     ~Application();

     int init(JNIEnv *env, const char* apkPath, const char* externalStorageDir,
    		 	 const char* stateDir, const char* sramDir);
     int initGraphics();
     int initAudioBuffers(const int sizeInSamples);
     void setAudioSampleRate(int rate);
     void destroy();

     void processInput();

     int loadROM(const char* filename);
     void closeROM();
     void resetROM();

     void saveSRam(const char* romName);
     void loadSRam(const char* romName);
     void saveState(const int i);
     void loadState(const int i);
     void selectState(const int i);

     void step(const JNIEnv *env);
     void draw(const JNIEnv *env);

     void setAudioEnabled(const bool b);
     size_t readAudio(jshort* in, const size_t samples);
     short* getAudioBuffer() { return _audioBuffer; }
     size_t getCurrentEmuSamples() { return _ssize; }
     size_t getAudioBufferSize() { return _audioBufferSize; }

     void setFrameSkip(int i)
     {
          if (i < 0) i = 0;
          if (i > 9) i = 9;

          _frameSkip = i;
     }

     bool isRomLoaded() { return _romLoaded; }
     bool isInitialized() { return _initialized; }
     bool isAudioInit() { return _audioInitialized; }

     void setGenPlusVideoChanged();

     GraphicsDriver Graphics;
     InputHandler Input;
private:
     bool _initialized;
     bool _romLoaded;
     bool _fceuInitialized;
     bool _audioInitialized;

     double _timeStart;
     double _timeEnd;
     double _timeDelta;

     int _frameSkip;
     int _frameSkipCount;

     char* _apkPath;
     char* _stateDir;
     char* _sramDir;
     char* _currentRom;

     // video
     float _viewPortW;
     float _viewPortH;
     uint32_t _screenBuff[EMU_RENDER_TEXTURE_WIDTH*EMU_RENDER_TEXTURE_HEIGHT] __attribute__ ((aligned (4)));

     // audio
     int32_t _ssize;
     int _sampleRate;
     Resampler *_resampler;
     unsigned _emuSamples;
     unsigned _tmpSamples;
     #define SB_SIZE 2048
	 #define GB_SAMPLES (35112+2064)
     short _audioBuffer[SB_SIZE];
     uint32_t _gbAudioBuffer[GB_SAMPLES];

     // for fceu input
     uint32_t _JSReturn;
     void *_InputDPR;

     size_t _audioBufferSize;

     int makePath(const char* dirName, char* outBuffer);
};
